package com.mutouren.modules.datapush.netty;

import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.util.Map;

import org.apache.commons.lang3.math.NumberUtils;

import com.mutouren.common.log.LogAlias;
import com.mutouren.common.log.LogManager;
import com.mutouren.common.log.Logger;
import com.mutouren.common.utils.StringUtils;
import com.mutouren.modules.datapush.ServerProxy;
import com.mutouren.modules.datapush.SpringContextHelper;
import com.mutouren.modules.datapush.base.DataPushLogAlias;
import com.mutouren.modules.datapush.base.PushMessage;
import com.mutouren.modules.datapush.config.ConfigManager;
import com.mutouren.modules.datapush.config.ConfigUpdateType;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpUtil;

public class HttpServerInboundHandler2 extends SimpleChannelInboundHandler<HttpObject> {
	
	private ServerProxy serverProxy = (ServerProxy)SpringContextHelper.getBean("serverProxy");
	private HttpRequest request;
	
	private final static Logger runLogger = LogManager.getLogger(LogAlias.SystemRun.name());
	private final static Logger errorLogger = LogManager.getLogger(LogAlias.SystemError.name());	
	private final static Logger ReceiveLogger = LogManager.getLogger(DataPushLogAlias.DataPushReceive.name());	
	
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
		byte[] bufMessage = new byte[0];
		
		try {
	        if (msg instanceof HttpRequest) {
	        	request = (HttpRequest) msg;
	        }
	        
	        if (msg instanceof HttpContent) {
	            HttpContent content = (HttpContent) msg;
	            ByteBuf buf = content.content();
	            bufMessage = new byte[buf.readableBytes()];            
	            buf.readBytes(bufMessage);
	            
	            String result = processMessage(request, bufMessage);
	            writeResponse(ctx, result);
	        }
		} catch (Throwable t) {
			errorLogger.error("HttpServerInboundHandler2 channelRead0 error", t);
		} finally {
			writeReceiveLog(ctx, request, bufMessage);
		}
	}
	
	private void writeResponse(ChannelHandlerContext ctx, String info) throws UnsupportedEncodingException {
        FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1,
                OK, Unpooled.wrappedBuffer(info.getBytes("UTF-8")));
        
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH,response.content().readableBytes());
        
        if ((request != null) && HttpUtil.isKeepAlive(request)) {
        	response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
        }
        ctx.write(response);
        ctx.flush();
	}
		
	private String processMessage(HttpRequest request, byte[] content) {
		final String sendUrl = "/mtr-datapush-server-web/api/send";
		final String configUrl = "/mtr-datapush-server-web/api/config";
		
		if ((request == null) || (content == null)) return "request or content is null";
		
		String url = request.uri();
		
		if (url.indexOf(sendUrl) >= 0) {
			return doSend(content);
		} else if (url.indexOf(configUrl) >= 0) {
			return doConfig(url);
		} else {
			return "no matching url";
		}
	}
	
	private String doSend(byte[] content) {
		String result = "ok";
		try {
			PushMessage message = PushMessage.decode(content);
			boolean isSuccess = serverProxy.receive(message);
			if (isSuccess == false) {
				result = "fail: out of maxPermitSize";
			}
		} catch (Throwable t) {
			result = "fail: " + t.getMessage();
			errorLogger.error("HttpServerInboundHandler2 doSend error", t);
		}
		return result;
	}
	
	private String doConfig(String url) {
		String result = "ok";
		Map<String, String> mapParam = StringUtils.getParamatersByUrl(url);
		String updateType = mapParam.get("updateType");
		
		try {
			ConfigUpdateType type = ConfigUpdateType.toConfigUpdateType(NumberUtils.toByte(updateType, (byte)100));
			
			if (type == null) {
				result = "updateType params error, should between 0 and 2";	
			} else {
				ConfigManager.updateConfig(type);				
			}									
		} catch(Throwable t) {
			result = "fail: " + t.getMessage();
			errorLogger.error("HttpServerInboundHandler2 doConfig error", t);
		}		
		return result;
	}
	
	private void writeReceiveLog(ChannelHandlerContext ctx, HttpRequest request, byte[] content) {		
		if ((request == null) || (content == null)) return;
		
		InetSocketAddress address = (InetSocketAddress)ctx.channel().remoteAddress();
		ReceiveLogger.info(String.format("host:%s:%s, request:%s, content:%s", address.getHostName(), address.getPort(), 
				request, new String(content)));
	}
	
	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		super.channelActive(ctx);
		runLogger.info("mtr-ctx channelActive");
	}
	
	@Override
	public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
		super.handlerAdded(ctx);
		runLogger.info("mtr-ctx handlerAdded");
	}
	
	@Override
	public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
		super.handlerRemoved(ctx);
		runLogger.info("mtr-ctx handlerRemoved");
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
			throws Exception {
		cause.printStackTrace();
		ctx.channel().close();
		errorLogger.info("mtr-ctx exceptionCaught", cause);
	}

}
